#ifndef BITOPERA_H_
#define BITOPERA_H_

#include <type_traits>

namespace lxj
{
template<class T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
class BitOperator {
    T _n;

public:
    constexpr BitOperator(T n) : _n(n) {}
    BitOperator(const BitOperator& other) : _n(other._n) {}

    inline operator T() { return _n; }

    /* inline friend constexpr T operator+(const BitOperator a, const BitOperator b)
    {
        T eor   = a._n ^ b._n;
        T carry = (a._n & b._n) << 1;
        while (carry != 0) {
            T temp = eor;
            eor ^= carry;
            carry = (temp & carry) << 1;
        }
        return eor ^= carry;
    } */
    inline static constexpr T add(const BitOperator a, const BitOperator b)
    {
        T eor   = a._n ^ b._n;
        T carry = (a._n & b._n) << 1;
        while (carry != 0) {
            T temp = eor;
            eor ^= carry;
            carry = (temp & carry) << 1;
        }
        return eor ^= carry;
    }

    inline static constexpr T minus(const BitOperator a, const BitOperator b)
    {
        return add(a, neg(b));
    }

    inline static constexpr BitOperator neg(const BitOperator n)
    {
        const T notn = add(BitOperator(~(n._n)), BitOperator(1));
        return BitOperator(notn);
    }

    inline static constexpr T multiply(const BitOperator a, const BitOperator b)
    {
        T    ans(0);
        T    _a = a._n;
        auto _b = std::make_unsigned_t<T>(b._n);
        while (_b != 0) {
            if ((_b & 1) != 0) ans = add(BitOperator(ans), BitOperator(_a));
            _a <<= 1;
            _b >>= 1;
        }
        return ans;
    }

    inline static constexpr T division(const BitOperator a, const BitOperator b)
    {
        constexpr T width = multiply(BitOperator(sizeof(T)), BitOperator(8));
        const T     min   = T(1) << minus(BitOperator(width), BitOperator(1));
        if (a._n == min && b._n == min) return 1;
        if (a._n != min && b._n != min) return div(a, b);
        if (b._n == min) return 0;
        if (b._n == neg(1)._n) return ~min;

        BitOperator _a     = add(a, b._n > 0 ? b : neg(b));
        T           ans    = div(_a, b);
        T           offset = b._n > 0 ? neg(1)._n : 1;
        return add(BitOperator(ans), BitOperator(offset));
    }

    inline static constexpr T div(const BitOperator a, const BitOperator b)
    {
        constexpr T _size = multiply(BitOperator(sizeof(T)), BitOperator(8));
        T           _a    = a._n >= 0 ? a._n : neg(a)._n;
        T           _b    = b._n >= 0 ? b._n : neg(b)._n;
        T           ans(0);
        for (T i = minus(BitOperator(_size), BitOperator(2)); i >= 0;
             i   = minus(BitOperator(i), BitOperator(1))) {
            if ((_a >> i) >= _b) {
                ans |= T(1) << i;
                _a = minus(BitOperator(_a), BitOperator(_b << i));
            }
        }
        return a._n < 0 ^ b._n < 0 ? neg(BitOperator(ans))._n : ans;
    }
};
}   // namespace lxj

#endif